Xilinx XDMA驱动代码分析及用法 您所在的位置:网站首页 xilinx k7 pcie状态机调试 Xilinx XDMA驱动代码分析及用法

Xilinx XDMA驱动代码分析及用法

2023-07-18 22:59| 来源: 网络整理| 查看: 265

Xilinx XDMA驱动代码分析及用法

先简单的介绍一下,赛灵思的XDMA的驱动是用于做什么的、他的主要功能就类似与网卡pcie接口的网卡驱动、用于控制主机与fpga设备进行pcie的通讯。通讯的主要方式是设备文件的读写,这里不清楚的同学可以看一下我上一篇文章。通过控制设备文件的读写,操作驱动与fpga设备进行数据传输。

1、目录结构 zacha@Superman:~/nfs/xdma-debug/dma_ip_drivers-master/XDMA/linux-kernel$ tree -C . ├── COPYING ├── include │ └── libxdma_api.h ├── LICENSE ├── readme.txt ├── RELEASE ├── tests │ ├── data │ │ ├── datafile0_4K.bin │ │ ├── datafile1_4K.bin │ │ ├── datafile2_4K.bin │ │ ├── datafile_256K.bin │ │ ├── datafile_32M.bin │ │ ├── datafile3_4K.bin │ │ └── datafile_8K.bin │ ├── dma_memory_mapped_test.sh │ ├── dma_streaming_test.sh │ ├── load_driver.sh │ ├── perform_hwcount.sh │ └── run_test.sh ├── tools │ ├── \001 │ ├── dma_from_device.c │ ├── dma_to_device.c │ ├── dma_utils.c │ ├── Makefile │ ├── performance.c │ ├── perform_hwcount.sh │ └── reg_rw.c └── xdma ├── cdev_bypass.c ├── cdev_ctrl.c ├── cdev_ctrl.h ├── cdev_events.c ├── cdev_sgdma.c ├── cdev_sgdma.h ├── cdev_xvc.c ├── cdev_xvc.h ├── libxdma.c ├── libxdma.h ├── Makefile ├── version.h ├── xdma_cdev.c ├── xdma_cdev.h ├── xdma_mod.c ├── xdma_mod.h ├── xdma_thread.c └── xdma_thread.h 5 directories, 43 files zacha@Superman:~/nfs/xdma-debug/dma_ip_drivers-master/XDMA/linux-kernel$

Xilinx 官方的XDMA驱动的目录结构大致如上图所示,大致就是:xdma(驱动代码)、tools(测试工具)、tests(自动化测试脚本)、include(对外头文件)。

今天重点分析驱动的代码部分,也会简单的介绍一些测试文件代码的基本用法。

1.1 tests/tools

tools中的文件就是用于测试驱动mem读写、寄存器读写、等的工具。 tests中的文件 就是自动化运行脚本,分为两种测试方法,第一种是mem mapped 方式,第二种事streamming的方式,两种模式的区别在于DMA以及FPGA的传输方式不同。

1.2 xdma

xdma就是驱动部分的代码,我们先看一下驱动安装成功后,所生成的设备文件,然后对应设备文件去看驱动代码每部分的功能和控制逻辑。

2、驱动的文件与生成的设备 2.1

我们先看xdma_mod.c这个文件, 这个文件主要的功能,这部分代码的主要功能是驱动代码的整体控制入口,我们知道,整个驱动的通讯都是基于PCI协议进行通讯的,所有的总线协议在Linux下都是需要进行总线上设备注册的,所以这个代码主要的功能,就是进行pci总线初始化和注册、然后再 在总线上注册各个字符设备。

static struct pci_driver pci_driver = { .name = DRV_MODULE_NAME, .id_table = pci_ids, .probe = probe_one, /*设备总线上的字符设备注册入口*/ .remove = remove_one, .err_handler = &xdma_err_handler, }; static int xdma_mod_init(void) { int rv; pr_info("%s", version); if (desc_blen_max > XDMA_DESC_BLEN_MAX) desc_blen_max = XDMA_DESC_BLEN_MAX; pr_info("desc_blen_max: 0x%x/%u, timeout: h2c %u c2h %u sec.\n", desc_blen_max, desc_blen_max, h2c_timeout, c2h_timeout); rv = xdma_cdev_init(); if (rv .owner = THIS_MODULE, .open = char_open, .release = char_close, .read = char_ctrl_read, .write = char_ctrl_write, .mmap = bridge_mmap, .unlocked_ioctl = char_ctrl_ioctl, };

用户层代码通过mmap io 进行mem映射, 然后通过read 和write 对bar空间的内存寄存器进行读写操作,以完成用户与设备的数据交互。

用户空间代码逻辑实现如下:

static int open_control(char *filename) { int fd; fd = open(filename, O_RDWR | O_SYNC); if(fd == -1) { printf("open control error\n"); return -1; } return fd; } static void *mmap_control(int fd,long mapsize) { void *vir_addr; vir_addr = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); return vir_addr; } static void write_control(void *base_addr,int offset,uint32_t val) { uint32_t writeval = htoll(val); *((uint32_t *)(base_addr+offset)) = writeval; } static uint32_t read_control(void *base_addr,int offset) { uint32_t read_result = *((uint32_t *)(base_addr+offset)); read_result = ltohl(read_result); return read_result; } int control_fd = open_control("/dev/xdma0_user"); control_base = mmap_control(control_fd,MAP_SIZE); frame_bytes = read_control(control_base,0x0a4); write_control(control_base, 0x0004, 0);

打开设备, mem映射至用户空间,寄存器读和写的操作

3.2 xdma_events

事件中断设备, 用于处理设备端发送中断事件的设备,read接口是以阻塞的方式实现的。 用法其实很简单,就是去读这个设备,能读完就说明有中断来了, 卡在读这里说明没有中断过来。 看用户层代码:这里读事件中断是用一个线程一直去读的,通过信号量去通知其他线程是否有中断过来。

void *c2h_event_process(void *param) { static int flag = 0; int fd = open_event("/dev/xdma0_events_0"); printf("c2h event thread running, c2h_event_fd = %d\n", fd); while(1) { if (read_event(fd)) { sem_post(&c2h_sem); printf("c2h get %d frame event\n",flag); } else{ /*timeout*/ } 3.3 xdma_c2h

数据传输读设备,方向是从fpga设备中读取数据过来。对应fpga的写通道。 用户端代码的逻辑是:调用设备的读接口,将读出的数据保存在预先分配的内存中,然后写进文件。 这种方式不建议在嵌入式设备中使用, 因为写数据到文件是比较耗时的, 这样就会影响读的速度,如果fpga读的速度过慢,那么就会导致fpga端的的数据传输fifo 满,数据就会丢失或者异常。

void *c2h_data_process(void *param) { int fd = open("/dev/xdma0_c2h_0",O_RDWR | O_NONBLOCK); printf("c2h data thread running, c2h_data_fd = %d\n", fd); /*读取的数据写文件*/ FILE *record_fp = fopen("/mnt/nfs/c2h_record.bin", "wb"); unsigned char *buf = new unsigned char[frame_bytes]; while(1) { sem_wait(&c2h_sem); read(fd, c2h_align_mem, trans_bytes); fwrite(c2h_align_mem, frame_bytes, 1, record_fp); } } 3.4 xdma_h2c

数据传输写设备,方向是将数据写进fpga设备中,对应fpga的读通道。 用户端写代码的逻辑就不阐述了,无非就是将预先写好的内容写到fpga的mem, 一般是DDR或者RAM看具体的逻辑设计。 直接上用户层代码。

void *h2c_data_process() { int fd; fd = open("/dev/xdma0_h2c_0",O_RDWR); while(1) { write(fd,h2c_align_mem,frame_bytes); sem_wait(&h2c_sem); } } 4.总结

最后整体的驱动文件与设备的功能,大致就将这么多。

相关的的驱动及测试代码,以及FPGA工程,已经上传至网盘,有需要的朋友可以自行下载。

网盘连接私信,看到就回,最晚第二个工作早上。 网盘内容请勿传播,有技术问题可私信加微信沟通。

最后,声明一下: 本人的博客很多基本上都是原创, 也有参考其他博文,也基本会在本人博文中有声明地址。 如果本文对您有帮助或者你想转载,请标明文章出处。文章作者:CSDN@蕉尼基



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有